home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 May: Tool Chest / Developer CD Series Tool Chest (Apple Computer)(May 1999).iso / Tool Chest / Development Kits / MPW etc / MPW-GM / MPW / Examples / PPCExamples / CPlusExamples / CPlusTESample / TApplication.cp < prev    next >
Encoding:
Text File  |  1998-12-03  |  16.0 KB  |  543 lines  |  [TEXT/MPS ]

  1. /*------------------------------------------------------------------------------
  2. #
  3. #    Apple Macintosh Developer Technical Support
  4. #
  5. #    MultiFinder-Aware Simple Application Framework
  6. #
  7. #    TApplication
  8. #
  9. #    TApplication.cp        -    C++ source
  10. #
  11. #    Copyright © 1989 Apple Computer, Inc.
  12. #    All rights reserved.
  13. #
  14. #    Versions:    
  15. #            1.20                    10/91
  16. #            1.10                     07/89
  17. #            1.00                     04/89
  18. #
  19. #    Components:
  20. #            TApplicationCommon.h    July 9, 1989
  21. #            TApplication.h            July 9, 1989
  22. #            TApplication.cp            July 9, 1989
  23. #            TApplication.r            July 9, 1989
  24. #            TDocument.h                July 9, 1989
  25. #
  26. #    TApplication is a rudimentary application framework
  27. #    for C++.
  28. #
  29. ------------------------------------------------------------------------------*/
  30.  
  31.  
  32. /*
  33. Segmentation strategy:
  34.  
  35.     This program has only one segment, since the issues
  36.     surrounding segmentation within a class's methods have
  37.     not been investigated yet. We DO unload the data
  38.     initialization segment at startup time, which frees up
  39.     some memory 
  40.  
  41. SetPort strategy:
  42.  
  43.     Toolbox routines do not change the current port. In
  44.     spite of this, in this program we use a strategy of
  45.     calling SetPort whenever we want to draw or make calls
  46.     which depend on the current port. This makes us less
  47.     vulnerable to bugs in other software which might alter
  48.     the current port (such as the bug (feature?) in many
  49.     desk accessories which change the port on OpenDeskAcc).
  50.     Hopefully, this also makes the routines from this
  51.     program more self-contained, since they don't depend on
  52.     the current port setting. 
  53.  
  54. Clipboard strategy:
  55.  
  56.     This program does not maintain a private scrap.
  57.     Whenever a cut, copy, or paste occurs, we import/export
  58.     from the public scrap to TextEdit's scrap right away,
  59.     using the TEToScrap and TEFromScrap routines. If we did
  60.     use a private scrap, the import/export would be in the
  61.     activate/deactivate event and suspend/resume event
  62.     routines. 
  63. */
  64.  
  65. // Mac Includes
  66. #include <Types.h>
  67. #include <Quickdraw.h>
  68. #include <Fonts.h>
  69. #include <Controls.h>
  70. #include <Windows.h>
  71. #include <Menus.h>
  72. #include <TextEdit.h>
  73. #include <Dialogs.h>
  74. #include <Devices.h>
  75. #include <Events.h> 
  76. #include <Scrap.h>
  77. #include <TextUtils.h>
  78. #include <MacMemory.h>
  79. #include <SegLoad.h>
  80. #include <Files.h>
  81. #include <OSUtils.h>
  82. #include <Traps.h>
  83. #include <LowMem.h>
  84. #include <Processes.h>
  85.  
  86. #include "TApplication.h"                    // use the local version. If you make changes
  87.                                             // that you've debugged and want other files
  88.                                             // to use, simple copy this header file into
  89.                                             // the C++ Includes folder (don't forget to
  90.                                             // copy the TApplication object library to the C++
  91.                                             // Libraries folder)!
  92.  
  93. // OSEvent is the event number of the suspend/resume and mouse-moved events sent
  94. // by MultiFinder. Once we determine that an event is an osEvent, we look at the
  95. // high byte of the message sent to determine which kind it is. To differentiate
  96. // suspend and resume events we check the resumeMask bit.
  97. const short kOsEvent = app4Evt;                // event used by MultiFinder
  98. const short kSuspendResumeMessage = 0x01;    // high byte of suspend/resume event message
  99. const short kClipConvertMask = 0x02;        // bit of message field clip conversion
  100. const short kResumeMask = 0x01;                // bit of message field for resume vs. suspend
  101. const short kMouseMovedMessage = 0xFA;        // high byte of mouse-moved event message
  102.  
  103. #ifndef powerc
  104.  
  105. extern "C"
  106.     // from MPW standard library
  107.         void _DataInit(void);                // sets up A5 globals
  108. };
  109. #endif
  110.  
  111. QDGlobals    qd;
  112.  
  113. /***********************************************************************/
  114. //
  115. // TApplication class declarations
  116. //
  117. /***********************************************************************/
  118.  
  119. //-----------------------------------------------------------------------
  120. // TApplication::TApplication -     
  121. //
  122.     TApplication::TApplication( void )
  123.     {
  124.         SysEnvRec envRec;
  125.         long stkNeeded, heapSize;
  126.     
  127.         // initialize Mac Toolbox components
  128.             InitGraf (&qd.thePort);
  129.  
  130.             InitFonts();
  131.             InitWindows();
  132.             InitMenus();
  133.             TEInit();
  134.             InitDialogs(nil);
  135.             InitCursor();
  136.     
  137. #ifndef powerc
  138.         // Unload data segment: note that _DataInit must not be in Main!
  139.             UnloadSeg((ProcPtr) _DataInit);
  140. #endif
  141.  
  142.         // ignore the error returned from SysEnvirons; even if an error occurred,
  143.         // the SysEnvirons glue will fill in the SysEnvRec
  144.             ( void ) SysEnvirons( curSysEnvVers, &envRec );
  145.     
  146.         // Are we running on a 128K ROM machine or better???
  147.             if ( envRec.machineType < 0 )
  148.                 BigBadError( kErrStrings,eWrongMachine );        // if not, alert & quit
  149.     
  150.         // if we need more stack space, get it now
  151.             stkNeeded = StackNeeded();
  152.             if (stkNeeded > StackSpace())
  153.             {
  154.                 // new address is heap size + current stack - needed stack
  155.                     SetApplLimit((Ptr) ((long) GetApplLimit() - stkNeeded + StackSpace()));
  156.             }
  157.     
  158.         // Check for minimum heap size
  159.             heapSize = (long) GetApplLimit() - (long) ApplicationZone();
  160.             if ( heapSize < HeapNeeded())
  161.                 BigBadError( kErrStrings, eSmallSize );
  162.     
  163.         // expand the heap so new code segments load at the top
  164.             MaxApplZone();
  165.     
  166.         // allocate an empty document list
  167.             fDocList = new TDocumentList;
  168.     
  169.         // check to see if WaitNextEvent is implemented
  170.             fHaveWaitNextEvent = TrapAvailable( _WaitNextEvent, ToolTrap );
  171.     
  172.         // initialize our class variables
  173.             fCurDoc = nil;
  174.             fDone = false;
  175.             fInBackground = false;
  176.             fMouseRgn = nil;
  177.             fWhichWindow = nil;
  178.             
  179.     } /* TApplication (constructor) */
  180.  
  181.  
  182. //-----------------------------------------------------------------------
  183. // TApplication::ExitLoop -     we're quitting the application; let's
  184. //                                do whatever needs to be done to clean up.
  185. //                                In our case, there isn't much to be done.
  186. //
  187.     void TApplication::ExitLoop( void )
  188.     {
  189.         fDone = true;
  190.     }
  191.  
  192.  
  193. //-----------------------------------------------------------------------
  194. // TApplication::EventLoop -     keep track of events and handle them
  195. //                                appropriately.
  196. //
  197.     void TApplication::EventLoop( void )
  198.     {
  199.         int gotEvent;
  200.         EventRecord tEvt;
  201.     
  202.         SetUp();                    // call setup routine
  203.         DoIdle();                    // do idle once
  204.     
  205.         while (fDone == false)
  206.           {
  207.             // always set up fWhichWindow before doing anything
  208.                 fWhichWindow = FrontWindow();
  209.                 
  210.             // see if window belongs to a document
  211.                 fCurDoc = fDocList->FindDoc(fWhichWindow);
  212.                 
  213.             // make sure we always draw into correct window
  214.                 SetPort(fWhichWindow);
  215.     
  216.             // let's allow others to use the cpu if they need (Multifinder friendliness).
  217.                 DoIdle();            // call idle time handler. this lets apps blink the caret
  218.                                     // or whatever else they wish to do
  219.             
  220.             //     determine if an event has occurred and what to do about it
  221.                 if ( fHaveWaitNextEvent )
  222.                 {
  223.                     gotEvent = WaitNextEvent( everyEvent, &tEvt, SleepVal(), fMouseRgn );
  224.                 }
  225.                 else
  226.                 {
  227.                     SystemTask();
  228.                     gotEvent = GetNextEvent( everyEvent, &tEvt );
  229.                 }
  230.                 fTheEvent = tEvt;
  231.     
  232.             // make sure we got a real event
  233.                 if ( gotEvent )
  234.                 {
  235.                     AdjustCursor();
  236.                     switch (fTheEvent.what)
  237.                     {
  238.                         case mouseDown :    DoMouseDown();
  239.                                             break;
  240.                                             
  241.                         case mouseUp :        DoMouseUp();
  242.                                             break;
  243.                                             
  244.                         case keyDown :
  245.                         case autoKey :        DoKeyDown();
  246.                                             break;
  247.                                             
  248.                         case updateEvt :    DoUpdateEvt();                
  249.                                             break;
  250.                                             
  251.                         case diskEvt :        DoDiskEvt();
  252.                                             break;
  253.                                             
  254.                         case activateEvt :    DoActivateEvt();
  255.                                             break;
  256.                                             
  257.                         case kOsEvent :        DoOSEvent();
  258.                                             break;
  259.                                             
  260.                         default :            break;
  261.                         
  262.                     } // end switch (fTheEvent.what)
  263.                 }
  264.                 
  265.             // update the cursor shape as needed after the event
  266.                 AdjustCursor();
  267.         }
  268.         // call cleanup handler
  269.         CleanUp();
  270.         
  271.     }  /* TApplication::EventLoop */
  272.  
  273.  
  274. //-----------------------------------------------------------------------
  275. // TApplication::DoKeyDown -     simple routine to handle key presses.
  276. //
  277.     void TApplication::DoKeyDown( void )
  278.     {
  279.         char key;
  280.         long mResult;
  281.     
  282.         key = (char) ( fTheEvent.message & charCodeMask );
  283.         if (( fTheEvent.modifiers & cmdKey ) && ( fTheEvent.what == keyDown ))
  284.         {
  285.             // only do command keys if we are not autokeying
  286.                 AdjustMenus();                    // make sure menus are up to date
  287.                 mResult = MenuKey( key );
  288.                 if ( mResult != 0 )                // if it wasn't a menu key, pass it through
  289.                 {
  290.                     DoMenuCommand( HiWrd( mResult ), LoWrd( mResult ));
  291.                     return;
  292.                 }
  293.         }
  294.         
  295.         if ( fCurDoc != nil )
  296.         {
  297.             EventRecord tEvt;
  298.     
  299.             // we copy event record so that we don't pass reference to object field 
  300.             tEvt = fTheEvent;
  301.             fCurDoc->DoKeyDown( &tEvt );
  302.         }
  303.           
  304.     }  /* TApplication::DoKeyDown */
  305.  
  306.  
  307. //-----------------------------------------------------------------------
  308. // TApplication::DoActivateEvt -     a window is becoming active. if it is
  309. //                                    one of ours, call the document's activate
  310. //                                    routine.
  311. //
  312.     void TApplication::DoActivateEvt( void )
  313.     {
  314.         // event record contains window ptr
  315.             fWhichWindow = (WindowPtr) fTheEvent.message;
  316.  
  317.         // see if window belongs to a document
  318.             fCurDoc = fDocList->FindDoc( fWhichWindow );
  319.             SetPort( fWhichWindow );
  320.     
  321.         if ( fCurDoc != nil )
  322.           fCurDoc->DoActivate(( fTheEvent.modifiers & activeFlag ) != 0 );
  323.     
  324.     }  /* TApplication::DoActivateEvt */
  325.  
  326.  
  327. //-----------------------------------------------------------------------
  328. // TApplication::DoUpdateEvt -     a window needs to be updated. If it is one
  329. //                                of ours, call the document's update routine
  330. //                                to redraw it.
  331. //
  332.     void TApplication::DoUpdateEvt(void)
  333.     {
  334.         // event record contains window ptr
  335.             fWhichWindow = (WindowPtr) fTheEvent.message;
  336.  
  337.         // see if window belongs to a document
  338.             fCurDoc = fDocList->FindDoc( fWhichWindow );
  339.             SetPort( fWhichWindow );
  340.         
  341.             if ( fCurDoc != nil )
  342.                 fCurDoc->DoUpdate();
  343.           
  344.     }  /* TApplication::DoUpdateEvt */
  345.  
  346.  
  347. //-----------------------------------------------------------------------
  348. // TApplication::DoSuspend -     although our suspend and resume routine are
  349. //                                identical, let's use two distinct routines
  350. //                                so that a subclass can choose to override one
  351. //                                without having to rewrite the other.
  352. //
  353.     void TApplication::DoSuspend( Boolean doClipConvert )
  354.     {
  355.         doClipConvert = false;        // this is here because I HATE compiler warnings!!
  356.         if (fCurDoc != nil)
  357.           fCurDoc->DoActivate( !fInBackground );
  358.           
  359.     }  /* TApplication::DoSuspend */
  360.  
  361.  
  362. //-----------------------------------------------------------------------
  363. // TApplication::DoResume -     although our suspend and resume routine are
  364. //                                identical, let's use two distinct routines
  365. //                                so that a subclass can choose to override one
  366. //                                without having to rewrite the other.
  367. //
  368.     void TApplication::DoResume( Boolean doClipConvert )
  369.     {
  370.         doClipConvert = false;        // this is here because I HATE compiler warnings!!
  371.         if ( fCurDoc != nil )
  372.           fCurDoc->DoActivate( !fInBackground );
  373.           
  374.     }  /* TApplication::DoResume */
  375.  
  376.  
  377. //-----------------------------------------------------------------------
  378. // TApplication::DoOSEvent -     handle multifinder events accordingly.
  379. //
  380.     void TApplication::DoOSEvent(void)
  381.     {
  382.         Boolean doConvert;
  383.         unsigned char evType;
  384.     
  385.         // is it a multifinder event?
  386.             evType = (unsigned char) (fTheEvent.message >> 24) & 0x00ff;
  387.             switch ( evType )                    // high byte of message is type of event
  388.             {                                     
  389.                 case kMouseMovedMessage :        DoIdle();                    // mouse-moved is also an idle event
  390.                                                 break;
  391.                     
  392.                 case kSuspendResumeMessage :    doConvert = ( fTheEvent.message & kClipConvertMask ) != 0;
  393.                                                 fInBackground = ( fTheEvent.message & kResumeMask ) == 0;
  394.                                                 
  395.                                                 // depending on whether or not we're in the background call suspend or resume
  396.                                                     if ( fInBackground )
  397.                                                         DoSuspend( doConvert );
  398.                                                     else
  399.                                                         DoResume( doConvert );
  400.                                                 
  401.                                                 break;
  402.             }
  403.         
  404.     }  /* TApplication::DoOSEvent */
  405.  
  406.  
  407. //-----------------------------------------------------------------------
  408. // TApplication::DoMouseDown -     simple routine to handle a mouse click.
  409. //
  410.     void TApplication::DoMouseDown( void )
  411.     {
  412.         long        mResult;
  413.         short        partCode;
  414.         WindowPtr    tWind;
  415.         EventRecord    tEvt;
  416.     
  417.         // gotta watch those object field dereferences
  418.             partCode = FindWindow( fTheEvent.where, &tWind );
  419.             fWhichWindow = tWind;
  420.             tEvt = fTheEvent;
  421.             switch ( partCode )
  422.             {
  423.                 case inSysWindow :    DoMouseInSysWindow();
  424.                                     break;
  425.                                     
  426.                 case inMenuBar :    AdjustMenus();
  427.                                     mResult = MenuSelect( tEvt.where );
  428.                                     if ( mResult != 0 )
  429.                                       DoMenuCommand(HiWrd( mResult ), LoWrd( mResult ));
  430.                                     break;
  431.                                     
  432.                 case inGoAway :        DoGoAway();                    
  433.                                     break;
  434.                                     
  435.                 case inDrag :        DoDrag();
  436.                                     break;
  437.                                     
  438.                 case inGrow :        if ( fCurDoc != nil )
  439.                                           fCurDoc->DoGrow( &tEvt );                    
  440.                                     break;
  441.                 case inZoomIn :
  442.                 case inZoomOut :    if (( TrackBox(fWhichWindow, tEvt.where, partCode )) && ( fCurDoc != nil ))
  443.                                         fCurDoc->DoZoom(partCode);
  444.                                     break;
  445.                                     
  446.                 case inContent :    // If window is not in front, make it so
  447.                                         if ( fWhichWindow != FrontWindow() )
  448.                                             SelectWindow(fWhichWindow);
  449.                                         else
  450.                                             if (fCurDoc != nil)
  451.                                                  fCurDoc->DoContent(&tEvt);                    
  452.                                     break;
  453.             }
  454.           
  455.     }  /* TApplication::DoMouseDown */
  456.  
  457.  
  458. //-----------------------------------------------------------------------
  459. // TApplication::DoDrag -     have the system track the mouse movements and
  460. //                            drag the window accordingly.
  461. //
  462.     void TApplication::DoDrag( void )
  463.     {
  464.         DragWindow( fWhichWindow, fTheEvent.where, &qd.screenBits.bounds );
  465.         
  466.     }  /* TApplication::DoDrag */
  467.  
  468.  
  469. //-----------------------------------------------------------------------
  470. // TApplication::DoGoAway -     a mousedown event occurred in the go away region
  471. //                                of the active window; continue tracking it. If
  472. //                                the mouse is released in the region, then close
  473. //                                the window.
  474. //
  475.     void TApplication::DoGoAway( void )
  476.     {
  477.         if ( TrackGoAway( fWhichWindow, fTheEvent.where ))            // was the mouse released in the goAway region?
  478.         {                                                            // yes, but is the window ours?
  479.             if ( fCurDoc != nil )
  480.             {                                                        // it is our window, let's close it
  481.                 fDocList->RemoveDoc( fCurDoc );
  482.                 fCurDoc->DoClose();
  483.             }
  484.             else                                                    // no, the window must belong to the system, let them handle it
  485.                 CloseDeskAcc(((WindowPeek) fWhichWindow )->windowKind );
  486.                 
  487.             // make sure our current document/window references are valid
  488.                 if ( fWhichWindow != nil )                            // does an active window remain? 
  489.                 {
  490.                     fCurDoc = fDocList->FindDoc( fWhichWindow );    // yes, update the current document pointer
  491.                     SetPort( fWhichWindow );                        // be sure to make future drawings to the new window
  492.                 }
  493.                 else
  494.                     fCurDoc = nil;                                    // no active window remains
  495.         }
  496.     }  /* TApplication::DoGoAway */
  497.  
  498.  
  499. //-----------------------------------------------------------------------
  500. // TApplication::TrapAvailable -     Check and see if the trap exists. 
  501. //
  502.     Boolean TApplication::TrapAvailable(short tNumber,TrapType tType)
  503.     {
  504.         // On 64K ROM machines, tType will be ignored.
  505.             return NGetTrapAddress( tNumber, tType ) != NGetTrapAddress( _Unimplemented, ToolTrap);
  506.         
  507.     }  /* TApplication::TrapAvailable */
  508.  
  509.  
  510. //-----------------------------------------------------------------------
  511. // TApplication::AlertUser -     Simple routine to display an alert dialog
  512. //                                using str# resources. Although this routine
  513. //                                exists and is used in this sample, a more
  514. //                                streamlined approach would be to create a
  515. //                                dialog library (or even an object) which
  516. //                                could be linked in. Using such a method,only
  517. //                                one source copy would exist.
  518. //
  519.     void TApplication::AlertUser( short errResID, short errCode )
  520.     {
  521.         Str255 message;
  522.     
  523.         SetCursor( &qd.arrow );
  524.         GetIndString( message, errResID, errCode );
  525.         ParamText(message, (ConstStr255Param) "\p", (ConstStr255Param) "\p", (ConstStr255Param) "\p" );
  526.         (void) Alert( rUserAlert, nil);
  527.         
  528.     }  /* TApplication::AlertUser */
  529.  
  530. //-----------------------------------------------------------------------
  531. // TApplication::BigBadError -     A variation of AlertUser which aborts to
  532. //                                the finder. 
  533. //
  534.     void TApplication::BigBadError(short errResID, short errCode)
  535.     {
  536.         AlertUser( errResID,errCode );
  537.         ExitToShell();
  538.         
  539.     }  /* TApplication::BigBadError */
  540.     
  541. // That's all, folks...
  542.